package com.foreveross.crawl.adapter.sub.impl20140402.v3.xiechen;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;

import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.adapter.sub.impl20140402.v3.XieChenAdapter;
import com.foreveross.crawl.common.util.DateUtil;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.single.SinglePlaneInfoEntity;
import com.foreveross.crawl.exception.FlightInfoNotFoundException;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.google.common.collect.Lists;

/**
 * 携程国内单程
 * 
 * @author xiangsf 2014-07-18
 *
 */
public class XieChenDomesticOneWayTrip {

	protected Log logger = LogFactory.getLog(getClass());
	private TaskModel taskQueue;
	private XieChenAdapter adapter;
	private String dataUrl = null;
	public XieChenDomesticOneWayTrip(XieChenAdapter adapter, TaskModel taskQueue) {
		this.adapter = adapter;
		this.taskQueue = taskQueue;
	}

	public List<Object> fetchData() throws Exception {
		List<SinglePlaneInfoEntity> singles = Lists.newArrayList();
		String html;
		JSONObject j;
		boolean noDirectFlights = false, noTransitFlights = false;
		try {
			this.fetchEnterPage();
			//直达航班
			html = this.fetchDirectResults();
			j = JSONObject.fromObject(html);
			//证明没有直达航班
			if(j.getJSONObject("Error") != null && !j.getJSONObject("Error").isNullObject() && j.getJSONObject("Error").getString("Code")!=null){
				if(j.getJSONObject("Error").getInt("Code") == 103)
					throw new FlightInfoNotFoundException();
				if(j.getJSONObject("Error").getInt("Code") == 102 )
					noDirectFlights = true;
			}else{
				singles.addAll(this.parseDirectFlights(j));
			}
			PlaneInfoEntityBuilder.buildLimitPrice(singles);
			if(noDirectFlights){//没有直达航班
				//中转航班
				html = this.fetchTransResults();
				j = JSONObject.fromObject(html);
				//证明没有航班
				if(j.getJSONObject("Error") != null && !j.getJSONObject("Error").isNullObject() && j.getJSONObject("Error").getString("Code")!=null && 
						j.getJSONObject("Error").getInt("Code") == 102){
					noTransitFlights = true;
				}else{
					singles.addAll(this.parseTransitFlights(j));
				}
			}
			//既没有直达，也没有中转航班，则抛出没有航班异常 
			if(noDirectFlights && noTransitFlights){
				throw new FlightInfoNotFoundException();
			}
			//设置源网页数据
			return Arrays.asList(singles.toArray());
		} finally {
			html = null;
			j = null;
		}
	}
	/**
	 * 抓取直达航班JSON结果
	 * http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?DCity1=YIW&ACity1=SJW&SearchType=S&DDate1=2014-10-17&CK=3AD56966C61F454DBD94C12536824E32&rk=265.5924225036368&r=0.9595392074226948
	 * */
	private String fetchDirectResults() throws Exception{
		HttpGet g;
		String html;
		StringBuffer url = null;
		try {
			url = new StringBuffer(dataUrl);
			url.append("&rk=").append(new Random(1).nextDouble()*1000).append("&r=").append(new Random(1).nextDouble());
			//http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?DCity1=BJS&ACity1=SZX&SearchType=S&DDate1=2014-09-06&r=0.732158165401361
			g = new HttpGet(url.toString());
			//2014-09-10　这个必须加上，否则请求不到数据
			StringBuffer refUrl = new StringBuffer("http://flights.ctrip.com/booking/");
				url.append(taskQueue.getFromCity()).append("-").append(taskQueue.getToCity()).append("-day-1.html");
			g.setHeader("Referer",refUrl.toString());
			g.setHeader("Host","flights.ctrip.com");
			g.setHeader("Connection","keep-alive");
			g.setHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
			//r.setHeader("Accept-Encoding","gzip, deflate");//使用压缩会出现乱码，所以这一行不能打开
			g.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
			html = adapter.excuteRequest(g);
			//设置源网页数据
			adapter.appendPageContents(html);
		} finally {
			g = null;
			url = null;
		}
		return html;
	}
	/**
	 * 抓取中转航班JSON结果
	 * http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?      DCity1=YIW&ACity1=SJW&SearchType=S&DDate1=2014-10-17&CK=3AD56966C61F454DBD94C12536824E32&rk=265.5924225036368&r=0.9595392074226948
	 * http://flights.ctrip.com/domesticsearch/search/SearchRecommendTransitFlights?DCity1=YIW&ACity1=SJW&SearchType=S&DDate1=2014-10-17&CK=3AD56966C61F454DBD94C12536824E32&r=0.7460301653550279
	 * */
	private String fetchTransResults() throws Exception{
		HttpGet g;
		String html;
		StringBuffer url = null;
		try {
			url = new StringBuffer(dataUrl.replace("SearchFirstRouteFlights", "SearchRecommendTransitFlights"));
			url.append("&r=").append(new Random(1).nextDouble());
			//http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?DCity1=BJS&ACity1=SZX&SearchType=S&DDate1=2014-09-06&r=0.732158165401361
			g = new HttpGet(url.toString());
			//2014-09-10　这个必须加上，否则请求不到数据
			StringBuffer refUrl = new StringBuffer("http://flights.ctrip.com/booking/");
				url.append(taskQueue.getFromCity()).append("-").append(taskQueue.getToCity()).append("-day-1.html");
			g.setHeader("Referer",refUrl.toString());
			g.setHeader("Host","flights.ctrip.com");
			g.setHeader("Connection","keep-alive");
			g.setHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
			//r.setHeader("Accept-Encoding","gzip, deflate");//使用压缩会出现乱码，所以这一行不能打开
			g.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
			html = adapter.excuteRequest(g);
			//设置源网页数据
			adapter.appendPageContents(html);
		} finally {
			g = null;
			url = null;
		}
		return html;
	}
	/**
	 * 请求查询进入页面，获得参数
	 * */
	private void fetchEnterPage() throws Exception{
		StringBuffer url = new StringBuffer("http://flights.ctrip.com/booking/");
		url.append(taskQueue.getFromCity()).append("-").append(taskQueue.getToCity()).append("-day-1.html");
		Map<String, String> params = new HashMap<String, String>();
		params.put("ReturnDate1", "");
		params.put("PassengerType", "ADU");
		params.put("PassengerQuantity", "1");
		params.put("DDate2", "");
		params.put("DDate1", taskQueue.getFlightDate());
		params.put("DCityName1", taskQueue.getFromCityName());
		params.put("DCity2", "");
		params.put("DCity1", taskQueue.getFromCity());
		params.put("ClassType", "");
		params.put("ACityName2", "");
		params.put("ACityName1", taskQueue.getToCityName());
		params.put("ACity2", "");
		params.put("ACity1", taskQueue.getToCity());
		HttpPost post = adapter.getBasePost(url.toString(), params);
		post.setHeader("Referer",url.toString());
		post.setHeader("Host","flights.ctrip.com");
		post.setHeader("Connection","keep-alive");
		post.setHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
		post.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		String html = adapter.excuteRequest(post);
		adapter.appendPageContents(html);
		dataUrl = RegHtmlUtil.regStr(html, "var url = \"(http://.*)\";.*var _searchCount_c");
	}
	/**
	 * 根据抓取的json解析出模型对象（直达）
	 * @param json
	 * @return
	 * @throws Exception
	 */
	private List<SinglePlaneInfoEntity> parseDirectFlights(JSONObject json) throws Exception {
		List<SinglePlaneInfoEntity> entitys = new ArrayList<SinglePlaneInfoEntity>();
		JSONArray flights;
		JSONObject company;
		JSONObject f;
		SinglePlaneInfoEntity entity;
		JSONArray scs;
		JSONObject s;
		CabinEntity cabinEntity;
		List<Double> prices;
		Double tax;
		try {
			company = json.getJSONObject("als");
			flights = json.getJSONArray("fis");
			for (int i = 0; i < flights.size(); i++) {
				prices = new ArrayList<Double>();
				f = flights.getJSONObject(i);
				entity = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, f.getString("alc"), company.getString(f.getString("alc")), company.getString(f.getString("alc")), null, null, f.getString("fn"), null, null, null, f.getJSONObject("cf")
						.getString("c"), SinglePlaneInfoEntity.class);
				entity.setStartTime(DateUtil.StringToDate("yyyy-MM-dd HH:mm:ss", f.getString("dt")));
				entity.setEndTime(DateUtil.StringToDate("yyyy-MM-dd HH:mm:ss", f.getString("at")));
				scs = f.getJSONArray("scs");
				// 税费解析。
				tax = f.getDouble("tax") + f.getDouble("of");
				for (int j = 0; j < scs.size(); j++) {
					s = scs.getJSONObject(j);
					Double price = s.getDouble("p");
					Double amount = tax == null ? null : price + tax; // 含税总价
					cabinEntity = PlaneInfoEntityBuilder.buildCabinInfo(getCabinType(s.getString("c"),/* s.getString("sc") */null), s.getString("sc"), null, tax + "", price + "", amount + "", null, null, CabinEntity.class);
					prices.add(s.getDouble("p"));
					entity.getCabins().add(cabinEntity);
				}
				// 这里去获取更多仓位信息 
				//2014-09-03去掉所有的取二级以上数据请求
				//setDomeCabinInfo(entity, prices, tax);
				entity.setTotalLowestPrice(this.getPriceByType(prices, "lower"));
				entity.setTotalHighestPrice(this.getPriceByType(prices, "hight"));
				entitys.add(entity);
			}
		} finally {
			prices = null;
			cabinEntity = null;
			scs = null;
			entity = null;
			f = null;
			company = null;
			flights = null;
		}
		logger.info("获得的直达航班数量:"+entitys.size());
		return entitys;
	}

	/**
	 * 根据抓取的json解析出模型对象（中转）
	 * @param json
	 * @return
	 * @throws Exception
	 */
	private List<SinglePlaneInfoEntity> parseTransitFlights(JSONObject json) throws Exception {
		List<SinglePlaneInfoEntity> entitys = new ArrayList<SinglePlaneInfoEntity>();
		JSONArray flights,fis;
		JSONObject company, apb;
		JSONObject f, t;
		SinglePlaneInfoEntity entity;
		Double tax = 0d;
		TransitEntity transit = null;
		try {
			company = json.getJSONObject("als");
			apb = json.getJSONObject("apb");
			flights = json.getJSONArray("tf");
			for (int i = 0; i < flights.size(); i++) {
				f = flights.getJSONObject(i).getJSONArray("Routes").getJSONObject(0);
				fis = f.getJSONArray("fis");
				f = fis.getJSONObject(0);
				entity = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, f.getString("alc"), company.getString(f.getString("alc")), company.getString(f.getString("alc")), null, null, f.getString("fn"), flights.getJSONObject(i).getString("p"), null, flights.getJSONObject(i).getString("p"), f.getJSONObject("cf")
						.getString("c"), SinglePlaneInfoEntity.class);
				for(int j = 0; j < fis.size(); j++){
					t = fis.getJSONObject(j);
					 transit = PlaneInfoEntityBuilder.buildTransitEntity(t.getString("fn"), null, t.getString("alc"), company.getString(t.getString("alc")), 
							company.getString(t.getString("alc")), t.getString("dpc"), 
							apb.getString(t.getString("dpc")+t.getString("dbid")), t.getString("apc"), 
							apb.getString(t.getString("apc")+t.getString("abid")), t.getJSONObject("cf").getString("c"));
					 transit.setStartTime(DateUtil.StringToDate("yyyy-MM-dd HH:mm:ss", t.getString("dt")));
					 transit.setEndTime(DateUtil.StringToDate("yyyy-MM-dd HH:mm:ss", t.getString("at")));
					entity.getTransits().add(transit);
					tax += t.getDouble("tax") + t.getDouble("of");
				}
				entity.setStartTime(DateUtil.StringToDate("yyyy-MM-dd HH:mm:ss", flights.getJSONObject(i).getString("dt")));
				entity.setEndTime(DateUtil.StringToDate("yyyy-MM-dd HH:mm:ss", flights.getJSONObject(i).getString("at")));
				entity.setTotalLowestTaxesPrice(tax);
				entity.setTotalHighestTaxesPrice(tax);

				entity.setSumLowestPrice(entity.getTotalLowestPrice()+entity.getTotalLowestTaxesPrice());
				entity.setSumHighestPrice(entity.getSumLowestPrice());
				entitys.add(entity);
			}
		} finally {
			entity = null;
			f = null;
			company = null;
			flights = null;
			apb = null;
			tax = null;
			transit = null;
		}
		logger.info("获得的中转航班数量:"+entitys.size());
		return entitys;
	}
	/**
	 * 根据页面参数名称获得舱位名称
	 * 
	 * @param s
	 * @param sc
	 * @return
	 */
	private String getCabinType(String s, String sc) {
		if (s == null && sc == null) {
			return "经济舱";// 最无奈的默认值
		}
		if (sc == null) {
			if ("Y".equals(s)) {
				return "经济舱";
			} else if ("F".equals(s)) {
				return "头等舱";
			} else {
				return "商务舱";
			}
		} else {
			return "经济舱";
		}
	}

	/**
	 * 根据type获得最低价或者最高价
	 * 
	 * @param prices
	 * @param type
	 * @return
	 */
	private Double getPriceByType(List<Double> prices, String type) {
		if (type == null) {
			return null;
		}
		if (prices == null || prices.isEmpty()) {
			return null;
		}
		if (prices.size() == 1) {
			return prices.get(0);
		}
		Collections.sort(prices);
		if ("hight".equals(type)) {
			return prices.get(prices.size() - 1);
		} else if ("lower".equals(type)) {
			return prices.get(0);
		} else {
			return null;
		}
	} 
}
